/*
 * Copyright (C) 2005-2011 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008-2011 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2006-2011 ScriptDev2 <http://www.scriptdev2.com/>
 *
 * Copyright (C) 2010-2011 ProjectSkyfire <http://www.projectskyfire.org/>
 * 
 * Copyright (C) 2011 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/* ScriptData
 SDName: Boss_KelThuzad
 SD%Complete: 80%
 SDComment: VERIFY SCRIPT
 SDCategory: Naxxramas
 EndScriptData */

#include "ScriptPCH.h"
#include "naxxramas.h"

enum Yells {
	//when shappiron dies. dialog between kel and lich king (in this order)
	SAY_SAPP_DIALOG1 = -1533084, //not used
	SAY_SAPP_DIALOG2_LICH = -1533085, //not used
	SAY_SAPP_DIALOG3 = -1533086, //not used
	SAY_SAPP_DIALOG4_LICH = -1533087, //not used
	SAY_SAPP_DIALOG5 = -1533088, //not used
	SAY_CAT_DIED = -1533089, //when cat dies, not used
	//when each of the 4 wing bosses dies
	SAY_TAUNT1 = -1533090, //not used
	SAY_TAUNT2 = -1533091, //not used
	SAY_TAUNT3 = -1533092, //not used
	SAY_TAUNT4 = -1533093, //not used
	SAY_SUMMON_MINIONS = -1533105, //start of phase 1
	SAY_AGGRO_1 = -1533094, //start of phase 2
	SAY_AGGRO_2 = -1533095,
	SAY_AGGRO_3 = -1533096,
	SAY_SLAY_1 = -1533097,
	SAY_SLAY_2 = -1533098,
	SAY_DEATH = -1533099,
	SAY_CHAIN_1 = -1533100,
	SAY_CHAIN_2 = -1533101,
	SAY_FROST_BLAST = -1533102,
	SAY_SPECIAL_1 = -1533106,
	SAY_SPECIAL_2 = -1533107,
	SAY_SPECIAL_3 = -1533108,
	SAY_REQUEST_AID = -1533103, //start of phase 3
	SAY_ANSWER_REQUEST = -1533104
//lich king answer
};
enum Event {
	EVENT_NONE,
	EVENT_BOLT,
	EVENT_NOVA,
	EVENT_CHAIN,
	EVENT_CHAINED_SPELL,
	EVENT_DETONATE,
	EVENT_FISSURE,
	EVENT_BLAST,

	EVENT_WASTE,
	EVENT_ABOMIN,
	EVENT_WEAVER,
	EVENT_ICECROWN,
	EVENT_TRIGGER,

	EVENT_PHASE,
};

enum Spells {
	SPELL_FROST_BOLT = 28478,
	H_SPELL_FROST_BOLT = 55802,
	SPELL_FROST_BOLT_AOE = 28479,
	H_SPELL_FROST_BOLT_AOE = 55807,
	SPELL_SHADOW_FISURE = 27810,
	SPELL_VOID_BLAST = 27812,
	SPELL_MANA_DETONATION = 27819,
	SPELL_FROST_BLAST = 27808,
	SPELL_CHAINS_OF_KELTHUZAD = 28410, //28408 script effect
	SPELL_KELTHUZAD_CHANNEL = 29423,
	SPELL_BERSERK = 28498,

	//spells for chained
	//warlock
	SPELL_CURSE_OF_AGONY = 47864,
	SPELL_SHADOW_BOLT = 47809,
	//shaman
	SPELL_EARTH_SHOCK = 49231,
	SPELL_HEALING_WAVE = 49273,
	//mage
	SPELL_FROST_FIREBOLT = 47610,
	SPELL_ARCANE_MISSILES = 42846,
	//rogue
	SPELL_HEMORRHAGE = 48660,
	SPELL_MUTILATE = 48666,
	//paladin
	SPELL_HOLY_SHOCK = 48825,
	SPELL_HAMMER_OF_JUSTICE = 10308,
	//priest
	SPELL_VAMPIRIC_TOUCH = 48160,
	SPELL_RENEW = 48068,
	//hunter
	SPELL_MULTI_SHOT = 49048,
	SPELL_VOLLEY = 58434,
	//warrior
	SPELL_BLADESTORM = 46924,
	SPELL_CLEAVE = 47520,
	//druid
	SPELL_MOONFIRE = 48463,
	SPELL_LIFEBLOOM = 48451,
	//death knight
	SPELL_PLAGUE_STRIKE = 49921,
	SPELL_HOWLING_BLAST = 51411,
};

enum Creatures {
	NPC_WASTE = 16427, // Soldiers of the Frozen Wastes
	NPC_ABOMINATION = 16428, // Unstoppable Abominations
	NPC_WEAVER = 16429, // Soul Weavers
	NPC_ICECROWN = 16441
// Guardians of Icecrown
};

const Position Pos[12] = {
		{ 3783.272705f, -5062.697266f, 143.711203f, 3.617599f }, //LEFT_FAR
		{ 3730.291260f, -5027.239258f, 143.956909f, 4.461900f }, //LEFT_MIDDLE
		{ 3757.6f, -5172.0f, 143.7f, 1.97f }, //WINDOW_PORTAL05
		{ 3759.355225f, -5174.128418f, 143.802383f, 2.170104f }, //RIGHT_FAR
		{ 3700.724365f, -5185.123047f, 143.928024f, 1.309310f }, //RIGHT_MIDDLE
		{ 3700.86f, -5181.29f, 143.928024f, 1.42f }, //WINDOW_PORTAL04
		{ 3754.431396f, -5080.727734f, 142.036316f, 3.736189f }, //LEFT_FAR
		{ 3724.396484f, -5061.330566f, 142.032700f, 4.564785f }, //LEFT_MIDDLE
		{ 3732.02f, -5028.53f, 143.92f, 4.49f }, //WINDOW_PORTAL02
		{ 3687.571777f, -5126.831055f, 142.017807f, 0.604023f }, //RIGHT_FAR
		{ 3707.990733f, -5151.450195f, 142.032562f, 1.376855f }, //RIGHT_MIDDLE
		{ 3782.76f, -5062.97f, 143.79f, 3.82f }, //WINDOW_PORTAL03
		};

//creatures in corners
//Unstoppable Abominations
#define MAX_ABOMINATIONS                        21
const Position PosAbominations[MAX_ABOMINATIONS] = { { 3755.52f, -5155.22f,
		143.480f, 2.0f }, { 3744.35f, -5164.03f, 143.590f, 2.00f }, { 3749.28f,
		-5159.04f, 143.190f, 2.0f },
		{ 3774.47f, -5076.28f, 143.528f, 2.15912f }, { 3765.94f, -5074.15f,
				143.186f, 3.77233f },
		{ 3763.15f, -5063.36f, 143.694f, 3.77233f }, { 3737.81f, -5045.69f,
				143.709f, 4.9033f },
		{ 3728.13f, -5045.01f, 143.355f, 1.45069f }, { 3721.56f, -5048.35f,
				143.542f, 1.45069f },
		{ 3689.55f, -5049.66f, 143.637f, 5.2104f }, { 3681.71f, -5053.03f,
				143.242f, 2.47957f },
		{ 3677.64f, -5061.44f, 143.358f, 2.47957f }, { 3654.2f, -5090.87f,
				143.469f, 1.0313f }, { 3650.39f, -5097.45f, 143.496f, 2.5047f },
		{ 3658.7f, -5103.59f, 143.607f, 3.3278f }, { 3659.02f, -5133.97f,
				143.624f, 3.84538f },
		{ 3666.33f, -5139.34f, 143.183f, 3.84538f }, { 3669.74f, -5149.63f,
				143.678f, 0.528643f },
		{ 3695.53f, -5169.53f, 143.671f, 2.11908f }, { 3701.98f, -5166.51f,
				143.395f, 1.24257f },
		{ 3709.62f, -5169.15f, 143.576f, 5.97695f }, };

//Soldiers of the Frozen Wastes
#define MAX_WASTES                              49
const Position PosWastes[MAX_WASTES] = {
		{ 3754.41f, -5147.24f, 143.204f, 2.0f }, { 3754.68f, -5156.17f,
				143.418f, 2.0f }, { 3757.91f, -5160.12f, 143.503f, 2.0f }, {
				3752.67f, -5164.6f, 143.395f, 2.0f }, { 3745.42f, -5164.47f,
				143.565f, 2.74587f }, { 3741.2f, -5155.92f, 143.17f, 5.29134f },
		{ 3746.57f, -5148.82f, 143.176f, 5.07772f }, { 3778.14f, -5070.1f,
				143.568f, 3.16208f },
		{ 3775.09f, -5078.97f, 143.65f, 2.81022f }, { 3773.54f, -5083.47f,
				143.758f, 3.21549f }, { 3765, -5078.29f, 143.176f, 4.36688f }, {
				3766.94f, -5072.63f, 143.184f, 5.27951f }, { 3762.68f,
				-5064.94f, 143.635f, 3.95297f }, { 3769.9f, -5059.94f, 143.74f,
				3.36549f }, { 3736.33f, -5042.18f, 143.643f, 5.9471f }, {
				3727.51f, -5040.58f, 143.502f, 0.871859f }, { 3719.89f,
				-5049.64f, 143.58f, 4.75172f }, { 3720.69f, -5044.43f, 143.662f,
				1.87245f }, { 3725.69f, -5048.99f, 143.363f, 2.48271f }, {
				3732.33f, -5054.01f, 143.44f, 3.59405f }, { 3738.09f, -5051.06f,
				143.718f, 4.70931f },
		{ 3682.76f, -5063.5f, 143.175f, 0.636238f }, { 3686.7f, -5060.58f,
				143.18f, 0.636238f },
		{ 3682.45f, -5057.21f, 143.184f, 5.61252f }, { 3677.57f, -5053.34f,
				143.369f, 1.52531f },
		{ 3677.3f, -5062.26f, 143.369f, 2.73482f }, { 3691.21f, -5053.02f,
				143.421f, 5.93218f },
		{ 3685.22f, -5053.34f, 143.314f, 4.70303f }, { 3652.11f, -5088.47f,
				143.555f, 0.793317f },
		{ 3648.23f, -5093.21f, 143.311f, 1.18837f }, { 3648.14f, -5100.11f,
				143.632f, 2.12221f },
		{ 3653.88f, -5099.7f, 143.558f, 3.04348f }, { 3661.23f, -5100.33f,
				143.42f, 4.08335f },
		{ 3663.49f, -5092.77f, 143.346f, 4.47134f }, { 3661.85f, -5087.99f,
				143.571f, 1.0148f },
		{ 3664.56f, -5149.01f, 143.532f, 0.0762528f }, { 3665.01f, -5142.04f,
				143.201f, 1.72009f },
		{ 3671.15f, -5142.92f, 143.174f, 4.81535f }, { 3670.18f, -5134.38f,
				143.177f, 5.37534f },
		{ 3664.33f, -5131.69f, 143.262f, 5.39576f }, { 3658.21f, -5133.63f,
				143.662f, 1.3863f }, { 3659.7f, -5144.49f, 143.363f, 2.32328f },
		{ 3705.71f, -5179.63f, 143.746f, 1.06743f }, { 3696.77f, -5177.45f,
				143.759f, 5.36748f },
		{ 3700.97f, -5173.13f, 143.52f, 3.26575f }, { 3708.53f, -5172.19f,
				143.573f, 3.26575f },
		{ 3712.49f, -5167.62f, 143.657f, 5.63295f }, { 3704.89f, -5161.84f,
				143.239f, 5.63295f },
		{ 3695.66f, -5164.63f, 143.674f, 1.54416f }, };

//Soul Weavers
#define MAX_WEAVERS                             7
const Position PosWeavers[MAX_WEAVERS] = { { 3752.45f, -5168.35f, 143.562f,
		1.6094f }, { 3772.2f, -5070.04f, 143.329f, 1.93686f }, { 3732.28f,
		-5032.88f, 143.771f, 3.08355f }, { 3689.05f, -5055.7f, 143.172f,
		6.09554f }, { 3649.45f, -5093.17f, 143.299f, 2.51805f }, { 3659.7f,
		-5144.49f, 143.363f, 4.08806f }, { 3704.71f, -5175.96f, 143.597f,
		3.36549f }, };

// predicate function to select not charmed target
struct NotCharmedTargetSelector: public std::unary_function<Unit *, bool> {
	NotCharmedTargetSelector() {
	}

	bool operator()(const Unit *pTarget) {
		return (!pTarget->isCharmed());
	}
};

class boss_kelthuzad: public CreatureScript {
public:
	boss_kelthuzad() :
			CreatureScript("boss_kelthuzad") {
	}

	struct boss_kelthuzadAI: public BossAI {
		boss_kelthuzadAI(Creature* c) :
				BossAI(c, BOSS_KELTHUZAD), spawns(c) {
			uiFaction = me->getFaction();
			me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK,
					true);
			me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_GRIP, true);
		}

		uint32 Phase;
		uint32 uiGuardiansOfIcecrownTimer;
		uint32 uiFaction;

		uint8 nGuardiansOfIcecrownCount;
		uint8 nAbomination;
		uint8 nWeaver;

		std::map<uint64, float> chained;

		uint64 PortalsGUID[4];
		uint64 KTTriggerGUID;

		SummonList spawns; // adds spawn by the trigger. kept in separated list (i.e. not in summons)

		void Reset() {
			_Reset();

			PortalsGUID[0] = PortalsGUID[1] = PortalsGUID[2] = PortalsGUID[3] =
					0;
			KTTriggerGUID = 0;

			me->setFaction(35);
			me->SetFlag(
					UNIT_FIELD_FLAGS,
					UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE
							| UNIT_FLAG_NOT_SELECTABLE);
			std::map<uint64, float>::const_iterator itr;
			for (itr = chained.begin(); itr != chained.end(); ++itr) {
				if (Player* charmed = Unit::GetPlayer(*me, (*itr).first))
					charmed->SetFloatValue(OBJECT_FIELD_SCALE_X, (*itr).second);
			}

			chained.clear();
			spawns.DespawnAll();

			FindGameObjects();

			if (GameObject *pKTTrigger = me->GetMap()->GetGameObject(KTTriggerGUID)) {
				pKTTrigger->ResetDoorOrButton();
				pKTTrigger->SetPhaseMask(1, true);
			}

			for (uint8 i = 0; i <= 3; ++i) {
				if (GameObject *pPortal = me->GetMap()->GetGameObject(PortalsGUID[i])) {
					if (!((pPortal->getLootState() == GO_READY)
							|| (pPortal->getLootState() == GO_NOT_READY)))
						pPortal->ResetDoorOrButton();
				}
			}

			nGuardiansOfIcecrownCount = 0;
			uiGuardiansOfIcecrownTimer = 5000; //5 seconds for summoning each Guardian of Icecrown in phase 3

			Phase = 0;
			nAbomination = 0;
			nWeaver = 0;
		}

		void KilledUnit() {
			DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me);
		}

		void JustDied(Unit* /*Killer*/) {
			_JustDied();

			DoScriptText(SAY_DEATH, me);

			std::map<uint64, float>::const_iterator itr;
			for (itr = chained.begin(); itr != chained.end(); ++itr) {
				if (Player* pPlayer = Unit::GetPlayer(*me, (*itr).first))
					pPlayer->SetFloatValue(OBJECT_FIELD_SCALE_X, (*itr).second);
			}
			chained.clear();
		}

		void EnterCombat(Unit* /*who*/) {
			me->setFaction(uiFaction);

			_EnterCombat();
			FindGameObjects();
			for (uint8 i = 0; i <= 3; ++i) {
				if (GameObject *pPortal = me->GetMap()->GetGameObject(PortalsGUID[i]))
					pPortal->ResetDoorOrButton();
			}
			DoCast(me, SPELL_KELTHUZAD_CHANNEL, false);
			DoScriptText(SAY_SUMMON_MINIONS, me);
			Phase = 1;
			me->SetFlag(
					UNIT_FIELD_FLAGS,
					UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE
							| UNIT_FLAG_NOT_SELECTABLE);
			me->SetFloatValue(UNIT_FIELD_COMBATREACH, 4);
			me->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 4);
			events.ScheduleEvent(EVENT_TRIGGER, 5000);
			events.ScheduleEvent(EVENT_WASTE, 15000);
			events.ScheduleEvent(EVENT_ABOMIN, 30000);
			events.ScheduleEvent(EVENT_WEAVER, 50000);
			events.ScheduleEvent(EVENT_PHASE, 228000);
		}

		void FindGameObjects() {
			PortalsGUID[0] =
					instance ? instance->GetData64(DATA_KELTHUZAD_PORTAL01) : 0;
			PortalsGUID[1] =
					instance ? instance->GetData64(DATA_KELTHUZAD_PORTAL02) : 0;
			PortalsGUID[2] =
					instance ? instance->GetData64(DATA_KELTHUZAD_PORTAL03) : 0;
			PortalsGUID[3] =
					instance ? instance->GetData64(DATA_KELTHUZAD_PORTAL04) : 0;
			KTTriggerGUID =
					instance ? instance->GetData64(DATA_KELTHUZAD_TRIGGER) : 0;
		}

		void UpdateAI(const uint32 diff) {
			if (!UpdateVictim())
				return;

			events.Update(diff);

			if (Phase == 1) {
				while (uint32 eventId = events.GetEvent()) {
					switch (eventId) {
					case EVENT_WASTE:
						DoSummon(NPC_WASTE, Pos[RAND(0, 3, 6, 9)]);
						events.RepeatEvent(urand(2000, 5000));
						break;
					case EVENT_ABOMIN:
						if (nAbomination < 8) {
							DoSummon(NPC_ABOMINATION, Pos[RAND(1, 4, 7, 10)]);
							nAbomination++;
							events.RepeatEvent(20000);
						} else
							events.PopEvent();
						break;
					case EVENT_WEAVER:
						if (nWeaver < 8) {
							DoSummon(NPC_WEAVER, Pos[RAND(0, 3, 6, 9)]);
							nWeaver++;
							events.RepeatEvent(25000);
						} else
							events.PopEvent();
						break;
					case EVENT_TRIGGER:
						if (GameObject *pKTTrigger = me->GetMap()->GetGameObject(KTTriggerGUID))
							pKTTrigger->SetPhaseMask(2, true);
						events.PopEvent();
						break;
					case EVENT_PHASE:
						events.Reset();
						DoScriptText(
								RAND(SAY_AGGRO_1, SAY_AGGRO_2, SAY_AGGRO_3),
								me);
						spawns.DespawnAll();
						me->RemoveFlag(
								UNIT_FIELD_FLAGS,
								UNIT_FLAG_NON_ATTACKABLE
										| UNIT_FLAG_DISABLE_MOVE
										| UNIT_FLAG_NOT_SELECTABLE);
						me->CastStop();

						DoStartMovement(me->getVictim());
						events.ScheduleEvent(EVENT_BOLT, urand(5000, 10000));
						events.ScheduleEvent(EVENT_NOVA, 15000);
						events.ScheduleEvent(EVENT_DETONATE,
								urand(30000, 40000));
						events.ScheduleEvent(EVENT_FISSURE,
								urand(10000, 30000));
						events.ScheduleEvent(EVENT_BLAST, urand(60000, 120000));
						if (getDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL)
							events.ScheduleEvent(EVENT_CHAIN,
									urand(30000, 60000));
						Phase = 2;
						break;
					default:
						events.PopEvent();
						break;
					}
				}
			} else {
				//start phase 3 when we are 45% health
				if (Phase != 3) {
					if (HealthBelowPct(45)) {
						Phase = 3;
						DoScriptText(SAY_REQUEST_AID, me);
						//here Lich King should respond to KelThuzad but I don't know which Creature to make talk
						//so for now just make Kelthuzad says it.
						DoScriptText(SAY_ANSWER_REQUEST, me);

						for (uint8 i = 0; i <= 3; ++i) {
							if (GameObject *pPortal = me->GetMap()->GetGameObject(PortalsGUID[i])) {
								if (pPortal->getLootState() == GO_READY)
									pPortal->UseDoorOrButton();
							}
						}
					}
				} else if (nGuardiansOfIcecrownCount < RAID_MODE(2, 4)) {
					if (uiGuardiansOfIcecrownTimer <= diff) {
						// TODO : Add missing text
						if (Creature* pGuardian = DoSummon(NPC_ICECROWN, Pos[RAND(2, 5, 8, 11)]))
							pGuardian->SetFloatValue(UNIT_FIELD_COMBATREACH, 2);
						++nGuardiansOfIcecrownCount;
						uiGuardiansOfIcecrownTimer = 5000;
					} else
						uiGuardiansOfIcecrownTimer -= diff;
				}

				if (me->HasUnitState(UNIT_STAT_CASTING))
					return;

				if (uint32 eventId = events.GetEvent()) {
					switch (eventId) {
					case EVENT_BOLT:
						DoCastVictim(
								RAID_MODE(SPELL_FROST_BOLT,
										H_SPELL_FROST_BOLT));
						events.RepeatEvent(urand(5000, 10000));
						break;
					case EVENT_NOVA:
						DoCastAOE(
								RAID_MODE(SPELL_FROST_BOLT_AOE,
										H_SPELL_FROST_BOLT_AOE));
						events.RepeatEvent(urand(15000, 30000));
						break;
					case EVENT_CHAIN: {
						uint32 count = urand(1, 3);
						for (uint8 i = 1; i <= count; i++) {
							Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM,
									1, 200, true);
							if (pTarget && !pTarget->isCharmed()
									&& (chained.find(pTarget->GetGUID())
											== chained.end())) {
								DoCast(pTarget, SPELL_CHAINS_OF_KELTHUZAD);
								float scale = pTarget->GetFloatValue(
										OBJECT_FIELD_SCALE_X);
								chained.insert(
										std::make_pair(pTarget->GetGUID(),
												scale));
								pTarget->SetFloatValue(OBJECT_FIELD_SCALE_X,
										scale * 2);
								events.ScheduleEvent(EVENT_CHAINED_SPELL, 2000); //core has 2000ms to set unit flag charm
							}
						}
						if (!chained.empty())
							DoScriptText(RAND(SAY_CHAIN_1, SAY_CHAIN_2), me);
						events.RepeatEvent(urand(100000, 180000));
						break;
					}
					case EVENT_CHAINED_SPELL: {
						std::map<uint64, float>::iterator itr;
						for (itr = chained.begin(); itr != chained.end();) {
							if (Unit* player = Unit::GetPlayer(*me, (*itr).first)) {
								if (!player->isCharmed()) {
									player->SetFloatValue(OBJECT_FIELD_SCALE_X,
											(*itr).second);
									std::map<uint64, float>::iterator next = itr;
									++next;
									chained.erase(itr);
									itr = next;
									continue;
								}

								if (Unit *pTarget = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, NotCharmedTargetSelector())) {
									switch (player->getClass()) {
									case CLASS_DRUID:
										if (urand(0, 1))
											player->CastSpell(pTarget,
													SPELL_MOONFIRE, false);
										else
											player->CastSpell(me,
													SPELL_LIFEBLOOM, false);
										break;
									case CLASS_HUNTER:
										player->CastSpell(
												pTarget,
												RAND(SPELL_MULTI_SHOT,
														SPELL_VOLLEY), false);
										break;
									case CLASS_MAGE:
										player->CastSpell(
												pTarget,
												RAND(SPELL_FROST_FIREBOLT,
														SPELL_ARCANE_MISSILES),
												false);
										break;
									case CLASS_WARLOCK:
										player->CastSpell(
												pTarget,
												RAND(SPELL_CURSE_OF_AGONY,
														SPELL_SHADOW_BOLT),
												true);
										break;
									case CLASS_WARRIOR:
										player->CastSpell(
												pTarget,
												RAND(SPELL_BLADESTORM,
														SPELL_CLEAVE), false);
										break;
									case CLASS_PALADIN:
										if (urand(0, 1))
											player->CastSpell(pTarget,
													SPELL_HAMMER_OF_JUSTICE,
													false);
										else
											player->CastSpell(me,
													SPELL_HOLY_SHOCK, false);
										break;
									case CLASS_PRIEST:
										if (urand(0, 1))
											player->CastSpell(pTarget,
													SPELL_VAMPIRIC_TOUCH,
													false);
										else
											player->CastSpell(me, SPELL_RENEW,
													false);
										break;
									case CLASS_SHAMAN:
										if (urand(0, 1))
											player->CastSpell(pTarget,
													SPELL_EARTH_SHOCK, false);
										else
											player->CastSpell(me,
													SPELL_HEALING_WAVE, false);
										break;
									case CLASS_ROGUE:
										player->CastSpell(
												pTarget,
												RAND(SPELL_HEMORRHAGE,
														SPELL_MUTILATE), false);
										break;
									case CLASS_DEATH_KNIGHT:
										if (urand(0, 1))
											player->CastSpell(pTarget,
													SPELL_PLAGUE_STRIKE, true);
										else
											player->CastSpell(pTarget,
													SPELL_HOWLING_BLAST, true);
										break;
									}
								}
							}
							++itr;
						}

						if (chained.empty())
							events.PopEvent();
						else
							events.RepeatEvent(5000);

						break;
					}
					case EVENT_DETONATE: {
						std::vector<Unit*> unitList;
						std::list<HostileReference*> *threatList =
								&me->getThreatManager().getThreatList();
						for (std::list<HostileReference*>::const_iterator itr =
								threatList->begin(); itr != threatList->end();
								++itr) {
							if ((*itr)->getTarget()->GetTypeId()
									== TYPEID_PLAYER
									&& (*itr)->getTarget()->getPowerType()
											== POWER_MANA
									&& (*itr)->getTarget()->GetPower(POWER_MANA))
								unitList.push_back((*itr)->getTarget());
						}

						if (!unitList.empty()) {
							std::vector<Unit*>::const_iterator itr =
									unitList.begin();
							advance(itr, rand() % unitList.size());
							DoCast(*itr, SPELL_MANA_DETONATION);
							DoScriptText(
									RAND(SAY_SPECIAL_1, SAY_SPECIAL_2,
											SAY_SPECIAL_3), me);
						}

						events.RepeatEvent(urand(20000, 50000));
						break;
					}
					case EVENT_FISSURE:
						if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0))
							DoCast(pTarget, SPELL_SHADOW_FISURE);
						events.RepeatEvent(urand(10000, 45000));
						break;
					case EVENT_BLAST:
						if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, RAID_MODE(1, 0), 0, true))
							DoCast(pTarget, SPELL_FROST_BLAST);
						if (rand() % 2)
							DoScriptText(SAY_FROST_BLAST, me);
						events.RepeatEvent(urand(30000, 90000));
						break;
					default:
						events.PopEvent();
						break;
					}
				}

				DoMeleeAttackIfReady();
			}
		}
	};

	CreatureAI* GetAI(Creature* pCreature) const {
		return new boss_kelthuzadAI(pCreature);
	}
};

class at_kelthuzad_center: public AreaTriggerScript {
public:
	at_kelthuzad_center() :
			AreaTriggerScript("at_kelthuzad_center") {
	}

	bool OnTrigger(Player* pPlayer, const AreaTriggerEntry * /*at*/) {
		if (pPlayer->isGameMaster())
			return false;

		InstanceScript* pInstance = pPlayer->GetInstanceScript();
		if (!pInstance || pInstance->IsEncounterInProgress()
				|| pInstance->GetBossState(BOSS_KELTHUZAD) == DONE)
			return false;

		Creature* pKelthuzad =
				CAST_CRE(Unit::GetUnit(*pPlayer, pInstance->GetData64(DATA_KELTHUZAD)));
		if (!pKelthuzad)
			return false;

		boss_kelthuzad::boss_kelthuzadAI* pKelthuzadAI =
				CAST_AI(boss_kelthuzad::boss_kelthuzadAI, pKelthuzad->AI());
		if (!pKelthuzadAI)
			return false;

		pKelthuzadAI->AttackStart(pPlayer);
		if (GameObject* trigger = pInstance->instance->GetGameObject(pInstance->GetData64(DATA_KELTHUZAD_TRIGGER))) {
			if (trigger->getLootState() == GO_READY)
				trigger->UseDoorOrButton();

			// Note: summon must be done by trigger and not by KT.
			// Otherwise, they attack immediately as KT is in combat.
			for (uint8 i = 0; i <= MAX_ABOMINATIONS; ++i) {
				if (Creature* sum = trigger->SummonCreature(NPC_ABOMINATION, PosAbominations[i])) {
					pKelthuzadAI->spawns.Summon(sum);
					sum->GetMotionMaster()->MoveRandom(9.0f);
					sum->SetReactState(REACT_DEFENSIVE);
				}
			}
			for (uint8 i = 0; i <= MAX_WASTES; ++i) {
				if (Creature* sum = trigger->SummonCreature(NPC_WASTE, PosWastes[i])) {
					pKelthuzadAI->spawns.Summon(sum);
					sum->GetMotionMaster()->MoveRandom(5.0f);
					sum->SetReactState(REACT_DEFENSIVE);
				}
			}
			for (uint8 i = 0; i <= MAX_WEAVERS; ++i) {
				if (Creature* sum = trigger->SummonCreature(NPC_WEAVER, PosWeavers[i])) {
					pKelthuzadAI->spawns.Summon(sum);
					sum->GetMotionMaster()->MoveRandom(9.0f);
					sum->SetReactState(REACT_DEFENSIVE);
				}
			}
		}

		return true;
	}
};

void AddSC_boss_kelthuzad() {
	new boss_kelthuzad();
	new at_kelthuzad_center();
}
